/*
 * SimpleState.java
 *
 * Stateroom - Java framework library for finite state machines
 * Copyright (C) 2009 by Matthew Werny
 * All Rights Reserved
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */
package net.iceflow.stateroom;

import net.iceflow.stateroom.interfaces.Model;
import net.iceflow.stateroom.interfaces.State;
import net.iceflow.stateroom.interfaces.TransitionedInDelegate;
import net.iceflow.stateroom.interfaces.TransitionedOutDelegate;

/**
 * Simplified implementation of the State interface that allows delegates to be optionally plugged in.
 * @param <M> Type used to represent the machine model
 */
public class SimpleState<M extends Model> implements State<M> {

   /** Delegate to be called when transitioning into this state. */
   private final TransitionedInDelegate<M> _transInDelegate;

   /** Delegate to be called when transitioning out of this state. */
   private final TransitionedOutDelegate<M> _transOutDelegate;

   /** Name of the state instance. */
   private final String _name;

   /**
    * Constructs a new SimpleState instance without any delegates.
    * @param name Name of the state
    */
   public SimpleState(final String name) {
      // Call the most complex constructor, assuming that both delegates are null
      this(name, null, null);
   }

   /**
    * Constructs a new SimpleState instance with an inbound transition delegates.
    * @param name Name of the state
    * @param transInDelegate Delegate to be called when transitioning into the state
    */
   public SimpleState(final String name, final TransitionedInDelegate<M> transInDelegate) {
      // Call the most complex constructor, assuming that the transition out delegates is null
      this(name, transInDelegate, null);
   }

   /**
    * Constructs a new SimpleState instance with an inbound transition delegates.
    * @param name Name of the state
    * @param transOutDelegate Delegate to be called when transitioning out of the state
    */
   public SimpleState(final String name, TransitionedOutDelegate<M> transOutDelegate) {
      // Proxy to the most complex constructor, assuming that the transition in delegates is null
      this(name, null, transOutDelegate);
   }

   /**
    * Constructs a new SimpleState instance with both inbound and outbound transition delegates.
    * @param name Name of the state
    * @param transInDelegate Delegate to be called when transitioning into the state
    * @param transOutDelegate Delegate to be called when transitioning out of the state
    */
   public SimpleState(final String name, final TransitionedInDelegate<M> transInDelegate, TransitionedOutDelegate<M> transOutDelegate) {
      // Validate that the name is not null
      Utility.validateNotNull(name, "name may not be null.");

      // Save the name of the state to be provided on request by the getter
      this._name = name;

      // If the passed in transition in delegate is null...
      if (transInDelegate == null) {
         // ... create and use a null delegate
         this._transInDelegate = new NullDelegate();
      } else {
         // Otherwise, use the provided delegate
         this._transInDelegate = transInDelegate;
      }

      // If the passed in transition out delegate is null...
      if (transOutDelegate == null) {
         // ... create and use a null delegate
         this._transOutDelegate = new NullDelegate();
      } else {
         // Otherwise, use the provided delegate
         this._transOutDelegate = transOutDelegate;
      }
   }

   /**
    * Handler for when transitioning into the state.
    * @param context Machine context containing the machine instance under consideration
    */
   @Override
   public void stateTransitionedIn(Context<M> context) {
      // Proxy to the delegate
      this._transInDelegate.handleStateTransitionedIn(context);
   }

   /**
    * Handler for when transitioning out of the state.
    * @param context Machine context containing the machine instance under consideration
    */
   @Override
   public void stateTransitionedOut(Context<M> context) {
      // Proxy to the delegate
      this._transOutDelegate.handleStateTransitionedOut(context);
   }

   /**
    * Getter for the name of the state.
    * @return State name
    */
   @Override
   public String getStateName() {
      // Return the name of the state
      return this._name;
   }

   /** Class that implements both transition delegate interfaces and takes no action when called. */
   private class NullDelegate implements TransitionedInDelegate<M>, TransitionedOutDelegate<M> {

      /**
       * Handler for when transitioning into the state.
       * @param context Machine context containing the machine instance under consideration
       */
      @Override
      public void handleStateTransitionedIn(Context<M> context) {
         // Intentionally do nothing
      }

      /**
       * Handler for when transitioning out of the state.
       * @param context Machine context containing the machine instance under consideration
       */
      @Override
      public void handleStateTransitionedOut(Context<M> context) {
         // Intentionally do nothing
      }
   }
}
